﻿

namespace ApiTemplate.Common
{
    public class StackExchangeRedisHelper : ICacheHelper
    {
        /// <summary>
        /// Redis数据库
        /// </summary>
        private readonly IDatabase _database;

        /// <summary>
        /// 消息订阅
        /// </summary>
        private readonly ISubscriber subscriber;

        private readonly IServer server;

        /// <summary>
        /// 构造
        /// </summary>
        public StackExchangeRedisHelper()
        {
            RedisConfig redisConfig = ConfigHelper.GetAppSetting().RedisConfig;
            ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true);
            ConnectionMultiplexer redisConnection = ConnectionMultiplexer.Connect(new ConfigurationOptions
            {
                EndPoints =
                {
                    {redisConfig.Host,redisConfig.Port }
                },
                SyncTimeout = 1000,
                AsyncTimeout = 1000,
                ConnectTimeout = 1000,
                User = redisConfig.User,
                Password = redisConfig.PassWord,
            });
            server = redisConnection.GetServer(redisConnection.GetEndPoints()[0]);
            _database = redisConnection.GetDatabase(redisConfig.Database);
            subscriber = redisConnection.GetSubscriber();
        }

        /// <summary>
        /// 判断key是否存在
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns>是否存在</returns>
        public bool Exists(string key)
        {
            return _database.KeyExists(key);
        }

        /// <summary>
        /// 从队列顶部移除
        /// </summary>
        /// <param name="key">队列名称</param>
        /// <returns>返回移除的对象</returns>
        public string ListLeftPop(string key)
        {
            return _database.ListLeftPop(key);
        }

        /// <summary>
        /// 从队列顶部移除
        /// </summary>
        /// <param name="key">队列名称</param>
        /// <returns>返回移除的对象</returns>
        public RedisValue[] ListLeftPop(string key, int count)
        {
            return _database.ListLeftPop(key, count);
        }

        /// <summary>
        /// 添加List
        /// </summary>
        /// <param name="key"></param>
        /// <param name="values"></param>
        public void ListRightPush(string key, string value)
        {
            _database.ListRightPush(key, value);
        }

        /// <summary>
        /// 获取字符串类型的值
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        /// <returns>缓存的结果，可能为null</returns>
        public string GetStringValue(string key, int expireTime = 10)
        {
            string val = _database.StringGet(key);
            if (!string.IsNullOrEmpty(val) && expireTime > 0)
            {
                //_database.StringSet(key, val, new TimeSpan(0, expireTime, 0));
            }
            return val;
        }

        /// <summary>
        /// 获取复杂类型的缓存值
        /// </summary>
        /// <typeparam name="TEntity">缓存类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        /// <returns>缓存的结果，可能为null</returns>
        public TEntity GetEntity<TEntity>(string key, int expireTime = 10) where TEntity : class
        {
            string json = _database.StringGet(key);
            if (!string.IsNullOrEmpty(json) && expireTime > 0)
            {
                return json.ToEntityFromJson<TEntity>();
            }
            return null;
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        public void Remove(string key)
        {
            _database.KeyDelete(key);
        }

        /// <summary>
        /// 设置一个字符串类型的缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存内容</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        public void SetEntity(string key, object value, int expireTime = 10)
        {
            _database.StringSet(key, value.ToJson(), new TimeSpan(0, expireTime, 0));
        }

        /// <summary>
        /// 设置一个复杂类型的缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存对象</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        public void SetString(string key, string value, int expireTime = 10)
        {
            _database.StringSet(key, value, new TimeSpan(0, expireTime, 0));
        }


        /// <summary>
        /// 发布消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">发送的管道</param>
        /// <param name="sendMessage">发送的消息内容</param>
        /// <returns></returns>
        public long RedisPublish<T>(string channel, T sendMessage)
        {
            return subscriber.Publish(channel, sendMessage.ToJson());
        }

        /// <summary>
        /// 订阅消息（强制队列）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">管道</param>
        /// <param name="action">接收消息之后执行的方法</param>
        public void RedisSubscribeQueue<T>(string channel, Action<ChannelMessage> action)
        {
            var queue = subscriber.Subscribe(channel);
            queue.OnMessage(action);
        }


        /// <summary>
        /// 订阅消息（不会严格按照队列的方式执行）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">管道</param>
        /// <param name="action">接收消息之后执行的方法</param>
        public void RedisSubscribe<T>(string channel, Action<string> action)
        {
            subscriber.Subscribe(channel, (redisChannel, redisValue) =>
            {
                action(redisValue);//接收管道消息，触发事件
            });
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="channel">订阅通道</param>
        public void Unsubscribe(string channel)
        {
            subscriber.Unsubscribe(channel);
        }

        /// <summary>
        /// 取消所有订阅
        /// </summary>
        public void UnsubscribeAll()
        {
            subscriber.UnsubscribeAll();
        }

        #region async
        /// <summary>
        /// 判断key是否存在
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <returns>是否存在</returns>
        public async Task<bool> ExistsAsync(string key)
        {
            return await _database.KeyExistsAsync(key);
        }

        /// <summary>
        /// 获取字符串类型的值
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        /// <returns>缓存的结果，可能为null</returns>
        public async Task<string> GetStringValueAsync(string key, int expireTime = 10)
        {
            TimeSpan timeSpan = new TimeSpan(0, expireTime, 0);
            return await _database.StringGetSetExpiryAsync(key, timeSpan);
        }

        /// <summary>
        /// 获取复杂类型的缓存值
        /// </summary>
        /// <typeparam name="TEntity">缓存类型</typeparam>
        /// <param name="key">缓存key</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        /// <returns>缓存的结果，可能为null</returns>
        public async Task<TEntity> GetEntityAsync<TEntity>(string key, int expireTime = 10) where TEntity : class
        {
            string value = await GetStringValueAsync(key, expireTime);
            if (!string.IsNullOrEmpty(value))
            {
                return value.ToEntityFromJson<TEntity>();
            }
            return null;
        }

        /// <summary>
        /// 移除缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        public async Task RemoveAsync(string key)
        {
            await _database.KeyDeleteAsync(key);
        }

        /// <summary>
        /// 设置一个字符串类型的缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存内容</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        public async Task SetEntityAsync(string key, object value, int expireTime = 10)
        {
            TimeSpan timeSpan = new TimeSpan(0, expireTime, 0);
            await _database.StringSetAsync(key, value.ToJson(), timeSpan);
        }

        /// <summary>
        /// 设置一个复杂类型的缓存
        /// </summary>
        /// <param name="key">缓存key</param>
        /// <param name="value">缓存对象</param>
        /// <param name="expireTime">滑动过期时间；单位（分钟）</param>
        public async Task SetStringAsync(string key, string value, int expireTime = 10)
        {
            TimeSpan timeSpan = new TimeSpan(0, expireTime, 0);
            await _database.StringSetAsync(key, value, timeSpan);
        }

        /// <summary>
        /// 发布消息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">发送的管道</param>
        /// <param name="sendMessage">发送的消息内容</param>
        /// <returns></returns>
        public async Task<long> RedisPublishAsync<T>(string channel, T sendMessage)
        {
            return await subscriber.PublishAsync(channel, sendMessage.ToJson());
        }

        /// <summary>
        /// 订阅消息（强制队列）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">管道</param>
        /// <param name="action">接收消息之后执行的方法</param>
        public async Task RedisSubscribeQueueAsync<T>(string channel, Action<ChannelMessage> action)
        {
            var queue = await subscriber.SubscribeAsync(channel);
            queue.OnMessage(action);
        }

        /// <summary>
        /// 订阅消息（不会严格按照队列的方式执行）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="channel">管道</param>
        /// <param name="action">接收消息之后执行的方法</param>
        public async Task RedisSubscribeAsync<T>(string channel, Action<string> action)
        {
            await subscriber.SubscribeAsync(channel, (redisChannel, redisValue) =>
            {
                action(redisValue);//接收管道消息，触发事件
            });
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="channel">订阅通道</param>
        public async Task UnsubscribeAsync(string channel)
        {
            await subscriber.UnsubscribeAsync(channel);
        }

        /// <summary>
        /// 取消所有订阅
        /// </summary>
        public async Task UnsubscribeAllAsync()
        {
            await subscriber.UnsubscribeAllAsync();
        }

        /// <summary>
        /// 获取所有的缓存key
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<List<string>> GetAllKeyAsync()
        {
            List<string> result = new();
            var keys = server.Keys();
            foreach (var item in keys)
            {
                result.Add(item);
            }
            return result;
        }
        #endregion
    }
}
